﻿#region Copyright (C) 2007 Jens Winter

//Copyright (C) 2007 Jens Winter

//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.

//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//Lesser General Public License for more details.

//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#endregion

using System;
using Castle.Windsor;
using Flynn.Core.Activities;
using Flynn.Core.ConnectionFactories;
using Flynn.Core.ExtensionMethods;
using Flynn.Core.TaskResults;
using Flynn.Core.Tasks;

namespace Flynn.Core
{
    public class Engine : IEngine
    {
        private IWindsorContainer _container;

        public Engine()
        {
			InitializeContainer();
        }

    	public Engine(IProjectLoader projectLoader, ITaskExecutionService taskExecutionService)
        {
            if (projectLoader == null)
                throw new ArgumentNullException("projectLoader");

            if (taskExecutionService == null)
                throw new ArgumentNullException("taskExecutionService");

            _container = new WindsorContainer();

			_container.Kernel.AddComponentInstance<IProjectLoader>(typeof(IProjectLoader), projectLoader);
			_container.Kernel.AddComponentInstance<ITaskExecutionService>(typeof(ITaskExecutionService), taskExecutionService);
        }

    	public void RegisterVersioning(Type versioningType, string friendlyName)
        {
            _container.AddComponent(friendlyName.ToVersioningKey(), typeof(IVersioning), versioningType);
        }

    	public void RegisterDatabase(Type databaseType, string friendlyName)
        {
            _container.AddComponent(friendlyName.ToConnectionFactoryKey(), typeof(IConnectionFactory), databaseType);
        }

    	public PreparingDatabaseResult PrepareDatabase(string projectFile, string connectionString)
        {
            try
            {
                Project project = LoadProject(projectFile);

                ITaskExecutionService taskExecutionService = _container.Resolve<ITaskExecutionService>();

                return taskExecutionService.ExecutePrepareDatabaseTask(project, connectionString);
            }
            catch (LoadingProjectException e)
            {
                return PreparingDatabaseResult.Failure(string.Format("Failure: Project couldn't be loaded ({0})", e.Message));
            }
        }

    	public UpdatingDatabaseResult UpdateDatabase(string projectFile, string targetVersion, string connectionString)
        {
            try
            {
                Project project = LoadProject(projectFile);

                ITaskExecutionService taskExecutionService = _container.Resolve<ITaskExecutionService>();

                return taskExecutionService.ExecuteUpdateDatabaseTask(project, targetVersion, connectionString);
            }
            catch (LoadingProjectException e)
            {
                return UpdatingDatabaseResult.Failure(string.Format("Failure: Project couldn't be loaded ({0})", e.Message));
            }
        }

    	public CheckingDatabaseResult CheckDatabase(string projectFile, string connectionString)
        {
            try
            {
                Project project = LoadProject(projectFile);

                ITaskExecutionService taskExecutionService = _container.Resolve<ITaskExecutionService>();

                return taskExecutionService.ExecuteCheckDatabaseTask(project, connectionString);
            }
            catch (LoadingProjectException e)
            {
                return CheckingDatabaseResult.Failure(string.Format("Failure: Project couldn't be loaded ({0})", e.Message));
            }
        }

    	private void InitializeContainer()
    	{
    		_container = new WindsorContainer();

    		_container.AddComponent<IProjectLoader, ProjectLoader>();
    		_container.AddComponent<ITaskExecutionService, TaskExecutionService>();

    		// Tasks
    		_container.AddComponent<IPrepareDatabaseTask, PrepareDatabaseTask>();
    		_container.AddComponent<IUpdateDatabaseTask, UpdateDatabaseTask>();
    		_container.AddComponent<ICheckDatabaseTask, CheckDatabaseTask>();

    		// Activities
    		_container.AddComponent<IGetCurrentVersionActivity, GetCurrentVersionActivity>();
    		_container.AddComponent<ISetCurrentVersionActivity, SetCurrentVersionActivity>();
    		_container.AddComponent<IFilterAndExecuteUpdatesActivity, FilterAndExecuteUpdatesActivity>();
    		_container.AddComponent<IFilterUpdatesActivity, FilterUpdatesActivity>();
    		_container.AddComponent<IExecuteUpdatesActivity, ExecuteUpdatesActivity>();
    		_container.AddComponent<IExecuteUpdateActivity, ExecuteUpdateActivity>();
    		_container.AddComponent<IExecuteSqlStatementsActivity, ExecuteSqlStatementsActivity>();
    		_container.AddComponent<IExecuteSqlStatementActivity, ExecuteSqlStatementActivity>();
    	}

    	private Project LoadProject(string projectFile)
        {
            IProjectLoader projectLoader = _container.Resolve<IProjectLoader>();

            return projectLoader.LoadProject(projectFile);
        }
    }
}